// this file is intended to be included only from Vector.h.
#ifndef RS_VECTOR3_C_H
#define RS_VECTOR3_C_H


namespace rs
{

inline Vector3::Vector3(f32 x0, f32 y0, f32 z0)
: x(x0)
, y(y0)
, z(z0)
, w(0.0f)
{
}


inline Vector3::Vector3(const Vector3& rhs)
{
	x = rhs.x;
	y = rhs.y;
	z = rhs.z;
	w = rhs.w;
}


inline Vector3& Vector3::operator=(const Vector3& rhs)
{
	x = rhs.x;
	y = rhs.y;
	z = rhs.z;
	w = rhs.w;

	return *this;
}


inline Vector3& Vector3::operator+=(const Vector3& rhs)
{
	x += rhs.x;
	y += rhs.y;
	z += rhs.z;

	return *this;
}


inline Vector3& Vector3::operator-=(const Vector3& rhs)
{
	x -= rhs.x;
	y -= rhs.y;
	z -= rhs.z;

	return *this;
}


inline Vector3& Vector3::operator*=(const Vector3& rhs)
{
	x *= rhs.x;
	y *= rhs.y;
	z *= rhs.z;

	return *this;
}


inline Vector3& Vector3::operator*=(f32 rhs)
{
	x *= rhs;
	y *= rhs;
	z *= rhs;

	return *this;
}


inline Vector3& Vector3::operator/=(const Vector3& rhs)
{
	x /= rhs.x;
	y /= rhs.y;
	z /= rhs.z;

	return *this;
}


inline Vector3& Vector3::operator/=(f32 rhs)
{
	x /= rhs;
	y /= rhs;
	z /= rhs;

	return *this;
}


inline void Vector3::set(f32 x0, f32 y0, f32 z0)
{
	x = x0;
	y = y0;
	z = z0;
	w = 0.0f;
}


inline f32 Vector3::getX() const { return x; }
inline f32 Vector3::getY() const { return y; }
inline f32 Vector3::getZ() const { return z; }


inline Vector3& Vector3::normalize()
{
	const f32 length = this->length();

	if (length < RS_F32_EPSILON) {
		// already zero vector. do nothing.
	} else {
		this->operator /=(length);
	}

	return *this;
}


inline Vector3 Vector3::getNormalize() const
{
	const f32 length = this->length();

	if (length < RS_F32_EPSILON) {
		return Vector3(0.0f, 0.0f, 0.0f);
	} else {
		const f32 rl = 1.0f / length;
		return Vector3(x * rl, y * rl, z * rl);
	}
}


inline Vector3& Vector3::cross(const Vector3& rhs)
{
	const Vector3 tmp = getCross(rhs);
	x = tmp.x;
	y = tmp.y;
	z = tmp.z;
	return *this;
}


inline Vector3 Vector3::getCross(const Vector3& rhs) const
{
	return Vector3(y*rhs.z - z*rhs.y, z*rhs.x - x*rhs.z, x*rhs.y - y*rhs.x);
}


inline f32 Vector3::dot(const Vector3& rhs) const
{
	return x * rhs.x + y * rhs.y + z * rhs.z;
}


//;	f32 Vector3::dot(const Point3& rhs) const;


inline f32 Vector3::length() const
{
	return sqrtf(x*x + y*y + z*z);
}


inline f32 Vector3::lengthSq() const
{
	return (x*x + y*y + z*z);
}


inline Vector3 operator+(const Vector3& lhs, const Vector3& rhs)
{
	Vector3 ret = lhs;
	ret += rhs;
	return ret;
}


inline Vector3 operator-(const Vector3& lhs, const Vector3& rhs)
{
	Vector3 ret = lhs;
	ret -= rhs;
	return ret;
}


inline Vector3 operator*(const Vector3& lhs, const Vector3& rhs)
{
	Vector3 ret = lhs;
	ret *= rhs;
	return ret;
}


inline Vector3 operator*(const Vector3& lhs, f32 f)
{
	Vector3 ret = lhs;
	ret *= f;
	return ret;
}


inline Vector3 operator*(f32 f, const Vector3& rhs)
{
	Vector3 ret = rhs;
	ret *= f;
	return ret;
}


inline Vector3 operator/(const Vector3& lhs, const Vector3& rhs)
{
	Vector3 ret = lhs;
	ret /= rhs;
	return ret;
}


inline Vector3 operator/(const Vector3& lhs, f32 f)
{
	Vector3 ret = lhs;
	ret /= f;
	return ret;
}

} // namespace rs


#endif // #ifndef RS_VECTOR3_C_H
